<style>
svg {
  font-size: 14px;
}

#tooltip666.hidden {
  display: none;
}
#tooltip666 {
  width: 150px;
  position: absolute;
}
.h-menu-white{
  border:1px solid #EFEFEF;
}
#tooltip666 p {
  margin: 0;
  font-family: sans-serif;
  font-size: 10px;
}
#edgeMenu{
   width: 150px;
   position: absolute;
}
#edgeMenu .h-menu-white{
  margin-left: 7px;
  margin-top: -1px;
}
#edgeMenu .circle{
  display: block;
  height: 10px;
  width: 10px;
  border: 1px solid green;
  border-radius: 5px;
  background: #EFEFEF;
}
</style>
<template>
<div class="icons-vue h-panel frame-page">
    <div class="h-panel-bar">
      <span class="h-panel-title">流程图</span>
    </div>
    <div class="h-panel-body">
        <Modal v-model="opened" v-bind="params">
          <div slot="header">{{action=='edit'?'流程名称':''}}{{action=='add'?'添加分支节点':''}}</div>
          <div :style="{'height':'auto'}">
            <Form mode="block" ref="form" :validOnChange="validOnChange"
      :showErrorTip="showErrorTip"
      :rules="validationRules" :model="params">
              <FormItem label="名称" prop="title"><input type="text" v-model="params.title" @keyup.enter="confirm"></FormItem>
              <FormItem label="形状" prop="shape"><Select v-model="params.shape" :datas="shapes"></Select></FormItem>
            </Form>
          </div>
          <div slot="footer">
            <button class="h-btn" @click="close">取消</button>
            <button class="h-btn h-btn-primary" @click="confirm">确定</button>
          </div>
        </Modal>
        <HSwitch v-model="debug"></HSwitch>
        <div v-if="debug">
          currentNodeId:{{currentNodeId}} {{edge}} {{action}} <br/> nodes: {{list.nodes}} <br/>edges: {{list.edges}}
        </div>
        <div style="position:relative;height: 0;">
          <div id="edgeMenu" v-show="showMenu2">
            <span class="circle"></span>
            <Menu :datas="param2" @select="trigger2" className="h-menu-white"></Menu>
          </div>
          <div id="tooltip666" v-show="showMenu">
            <Menu :datas="param" @select="trigger" className="h-menu-white"></Menu>
          </div>
        </div>
        <div>
          <svg width="1000" height="1500">
            <g />
          </svg>
        </div>

    </div>
</div>
</template>


<script>
//D3和引入
import * as d3 from "d3";
import dagreD3 from "dagre-d3";
export default {
  data() {
    return {
      validationRules: {
        required:['title','shape']
      },
      showErrorTip: true,
      validOnChange: true,
      debug:false,
      action:'',
      edge:{},
      params:{
        title:'',
        shape:'',
      },
      showMenu2:false,
      showMenu:false,
      opened:false,
      currentNodeId:null,
      shapes:[{key:'rect',title:'rect'},{key:'circle',title:'circle'},{key:'diamond',title:'diamond'},{key:'ellipse',title:'ellipse'}],
      param: [{ title: '新增分支', key: 'add', icon: 'h-icon-plus' }, { title: '编辑节点', key: 'edit', icon: 'h-icon-edit' }, { title: '删除节点', key: 'delete', icon: 'h-icon-trash' }],
      param2: [{ title: '插入节点', key: 'insert', icon: 'h-icon-minus' }, { title: '删除线条', key: 'deleteEdge', icon: 'h-icon-trash' }],
      list: {
        nodes: [
      { id: 0, label: "流动人员", shape: "circle" },
      { id: 1, label: "安全筛查", shape: "rect" },
      { id: 2, label: "热像仪人体测温筛查", shape: "diamond" },
      { id: 3, label: "人工复测", shape: "rect" },
      { id: 4, label: "快速通过"},
      { id: 9, label: "紧急处理", shape: "ellipse" }
    ],
    edges: [
      { source: 0, target: 1, label: "" },
      { source: 1, target: 2, label: "" },
      { source: 2, target: 4, label: "正常" },
      { source: 2, target: 3, label: "不正常" },
      { source: 3, target: 9, label: "不正常" },
      { source: 3, target: 4, label: "正常" }
    ]

      },
      flagColor: "#eee",
      btnMsg: "开始",
      dis: false
    };
  },
  computed: {
  //这是一个控制流程图重新播放的方法
    nextNodeId() {
      let maxId = 0;
      this.list.nodes.forEach(item=>{
        if(item.id > maxId){
          maxId = item.id;
        }
      });
      maxId++;
      return maxId;
    },
    currentIndex() {
      let idx = 0;
      for (var i = this.list.nodes.length - 1; i >= 0; i--) {
        if(this.list.nodes[i].id == this.currentNodeId){
          idx = i;
          break;
        }
      }
      return idx;
    }    
  },
  mounted() {
    document.oncontextmenu = function () {
        return false;
    }
    document.onclick = ()=>{
      this.showMenu = false;
      this.showMenu2 = false;
    };
    this.draw();    

    // this.addNode();
  },
  methods: {
    confirm() {
      let validResult = this.$refs.form.valid();
      log(validResult);
      if (!validResult.result) {
        return false;
      }

      if(this.action == 'edit'){
        let item = Object.assign({},this.list.nodes[this.currentIndex]);
        item.label = this.params.title;
        item.shape = this.params.shape;
        this.list.nodes.splice(this.currentIndex,1,item);
      }else if(this.action == 'add'){
        let newNode = {label:this.params.title,shape:this.params.shape,id:this.nextNodeId}
        this.list.nodes.push(newNode);
        this.list.edges.push({source:this.currentNodeId,target:newNode.id,label:"未设置"});
      }else if(this.action == 'insert'){
        let newNode = {label:this.params.title,shape:this.params.shape,id:this.nextNodeId}
        this.list.nodes.push(newNode);
        let index = -1;
        for (var i = 0; i <= this.list.edges.length - 1; i++) {
          if(this.list.edges[i].source == this.edge.v && this.list.edges[i].target == this.edge.w){
            index = i;
            break;
          }
        }
        if(index!=-1){
          this.list.edges.splice(index,1,{source:this.edge.v,target:newNode.id,label:'未设置'},{source:newNode.id,target:this.edge.w,label:'未设置'});
        }
      }
      this.draw();    
      this.close();
    },
    close() {
      this.opened = false;
    },
    trigger2(code){
      this.showMenu2 = false;
      this.action = code.key;
      if(this.action != 'deleteEdge'){
        this.opened = true;
        return false;
      }
      let index = -1;
      for (var i = 0; i <= this.list.edges.length - 1; i++) {
        if(this.list.edges[i].source == this.edge.v && this.list.edges[i].target == this.edge.w){
          index = i;
          break;
        }
      }
      if(index!=-1){
        this.list.edges.splice(index,1);
        this.draw();
      }
    },
    trigger(code) {      
      this.showMenu = false;
      this.action = code.key;
      if(this.action != 'delete'){
        this.opened = true;
        return false;
      }
      if(this.list.nodes.length <= 1){
        this.$Message.warn('至少保留一个节点!');
        return false;
      }
      // 查询该节点的source
      let source = -1;
      let source_index = -1;
      for (var i = 0; i <= this.list.edges.length - 1; i++) {
        if(this.list.edges[i].target == this.currentNodeId){
          source_index = i;
          source = this.list.edges[i].source;
          break;
        }
      }
      // 如果有source  则该节点的targets的source变更为该source
      let targets_count = 0;
      for (var i = 0; i <= this.list.edges.length - 1; i++) {
        if(this.list.edges[i].source == this.currentNodeId){
          targets_count++;
          let target = this.list.edges[i].target; 
          let exist = this.list.edges.filter(item=>{
            return item.source == source && item.target == target;
          });
          if(exist.length > 0){
            this.list.edges[i].source = -1;
          }else{
            this.list.edges[i].source = source;
          }          
        }
      }      
      // 删除source_index 并排序 source == -1的
      if(source_index != -1){
        this.list.edges.splice(source_index,1)
      }
      if(!targets_count){
         this.list.edges = this.list.edges.filter(item=>{
          return item.target != this.currentNodeId;
        })
      }
      this.list.edges = this.list.edges.filter(item=>{
        return item.source != -1;
      })
      this.list.nodes.splice(this.currentIndex,1);
      this.draw(); 
    },
    draw() {
      let g = new dagreD3.graphlib.Graph(),dataset = this.list;
      //设置图
      g.setGraph({
        rankdir: 'TB'
      });
      dataset.nodes.forEach(item => {
        g.setNode(item.id, {
          //节点标签
          label: item.label,
          //节点形状
          shape: item.shape,
          //节点样式
          style: "fill:#fff;stroke:#000"
        })
      })
      dataset.edges.forEach(item => {
        g.setEdge(item.source, item.target, {
          //边标签
          label: item.label,
          //边样式
          style: "fill:#fff;stroke:#333;stroke-width:2px"
        })
      })
      // 创建渲染器
      let render = new dagreD3.render();
      // 选择 svg 并添加一个g元素作为绘图容器.
      let svgGroup = d3.select('svg').select('g');
      // 在绘图容器上运行渲染器生成流程图.
      this.initZoom(svgGroup,g);
      render(svgGroup, g);

      svgGroup.selectAll("g.edgePath")
       .on('mouseover',(d,e)=>{
        let points = g.edge(d).points;
        let point = points[Math.floor(points.length/2)];
        this.edge = d;
        this.showMenu2 = true;
        this.showMenu = false;
        d3.select("#edgeMenu")
            .attr(
              "style",
              "left:" +
                point.x +
                "px" +
                ";top:" +
                point.y +
                "px" +
                ";margin:-5px 0 0 -5px"
            );
       }).on("mouseout",(d,e)=>{

       });

      svgGroup.selectAll("g.node")
        //D3v6中的传参模式已更改，第一个参数是鼠标事件，第二个参数才是节点内容
        .on("contextmenu", (d,e) => {
          log(d,e);
          let current = g.node(d).elem;
          this.currentNodeId = d;      
          this.showMenu = true;
          this.showMenu2 = false;
          let find = this.list.nodes.filter(item=>{return item.id == d;})
          if(find.length > 0){
            this.params = {title:find[0].label,shape:find[0].shape};    
          }          
          d3.select(current).transition()
                        .duration(100)
                        .attr("fill","yellow").select('.label-container').attr("style","fill:red;stroke:#000");

          d3.select("#tooltip666")
            .attr(
              "style",
              "left:" +
                g.node(d).x +
                "px" +
                ";top:" +
                g.node(d).y +
                "px" +
                ";margin-top:" +
                10 +
                "px"
            )
            .select("#tooltip_value")
            .text(g.node(d).label);
        })
        .on("mouseout", (d,e) => {
          let current = g.node(d).elem;
          d3.select(current).transition()
                        .duration(100)
                        .attr("fill","#333").select('.label-container').attr("style","fill:#FFF;stroke:#000");
        });

    },
    initZoom(svgGroup,g) {
      // let svg = d3.select('svg')
      // // 建立拖拽缩放
      // let zoom = d3.zoom()
      //     .on("zoom", function () {
      //         svgGroup.attr("transform", d3.event.transform);
      //      });
      // svg.call(zoom);
    }
  }
};
</script>